/**
 * indexdb 数据库操作封装
 */
export class IndexDBDatabase {
  /**
   * @param {string} databaseName 数据库名称
   * @param {string|string[]} tableNames 表名
   * @param {number} version 数据库版本 - 注意：如果表名调整，需要修改版本号
   */
  constructor(databaseName, tableNames, version) {
    this.version = version
    this.databaseName = databaseName
    this.tableNames = Array.isArray(tableNames) ? tableNames : [tableNames]
    /**@type {IDBDatabase} */
    this.db = null
    /**@type {Map<string, IndexDBTabel>} */
    this.tableStoreMap = new Map()
  }
  /**
   * 获取数据库
   * @returns {Promise<IDBDatabase>}
   */
  async getDb() {
    if (!this.db) {
      this.db = await this.createDb()
    }
    return this.db
  }
  /**
   * 打开/新建数据库
   * @returns {Promise<IDBDatabase>}
   */
  createDb() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.databaseName, this.version)
      request.onsuccess = () => resolve(request.result)
      request.onerror = reject
      request.onupgradeneeded = (event) => {
        /**@type {IDBDatabase} */
        const db = event.target.result
        for (let item of this.tableNames) {
          // 创建表
          if (!db.objectStoreNames.contains(item)) {
            db.createObjectStore(item, { keyPath: 'id' })
          }
        }
      }
    })
  }
  /**
   * 获取表对象
   * @param {string} tableName 数据库里面的表名
   */
  getObjectStore(tableName) {
    if (!this.tableNames.includes(tableName)) {
      console.warn(`数据库 ${this.databaseName} 中不存在表 ${tableName} 这里默认取第一张表`)
      tableName = this.tableNames[0]
    }
    const table = new IndexDBTabel(this, tableName)
    this.tableStoreMap.set(tableName, table)
    return table
  }
}

/**
 * indexdb 表操作封装
 */
class IndexDBTabel {
  /**
   * @param {IndexDBDatabase} database 数据库对象
   * @param {string} tableName 表名称
   */
  constructor(database, tableName) {
    this.database = database
    this.tableName = tableName
  }

  /**
   * 表操作
   * @param {keyof IDBObjectStore} type 操作类型
   * @param {any} data 数据
   * @returns {Promise<Event>}
   */
  async tableStoreHandle(type, data) {
    const db = await this.database.getDb()
    const tableStore = db.transaction([this.tableName], 'readwrite').objectStore(this.tableName)
    return new Promise((resolve, reject) => {
      const request = tableStore[type](data)
      request.onsuccess = () => resolve(request)
      request.onerror = reject
    })
  }

  /**
   * 新增数据
   * @param {any} data 值
   */
  add(data) {
    return this.tableStoreHandle('add', { id: Math.random().toString(36).slice(2), ...data })
  }
  /**
   * 批量添加数据
   * @param {any[]} dataList
   */
  async bulkAdd(dataList) {
    const db = await this.database.getDb()
    const tableStore = db.transaction([this.tableName], 'readwrite').objectStore(this.tableName)
    const addItem = (data) => {
      return new Promise((resolve, reject) => {
        const request = tableStore.add(data)
        request.onsuccess = () => resolve(request)
        request.onerror = reject
      })
    }
    return Promise.all(dataList.map((item) => addItem(item)))
  }
  /**
   * 修改数据
   * @param {any} data 值
   */
  update(data) {
    return this.tableStoreHandle('put', data)
  }
  /**
   * 通过id获取数据
   * @param {string} id 键
   */
  async getById(id) {
    const res = await this.tableStoreHandle('get', id)
    return res.result
  }
  /**获取所有数据 */
  async getAll(id) {
    const res = await this.tableStoreHandle('getAll', id)
    return res.result
  }
  /**根据查询条件获取数据 */
  serchList(params, func) {
    const check = (data) => {
      if (typeof func == 'function') {
        return func(data)
      }
      return Object.keys(params).every((key) => {
        return data[key] === params[key]
      })
    }
    return new Promise((resolve, reject) => {
      this.database.getDb().then((db) => {
        const tableStore = db.transaction([this.tableName], 'readonly').objectStore(this.tableName)
        const data = []
        const q = tableStore.openCursor()
        q.onsuccess = (event) => {
          const cursor = event.target.result
          if (cursor) {
            if (check(cursor.value)) {
              data.push(cursor.value)
            }
            cursor.continue()
          } else {
            resolve(data)
          }
        }
        q.onerror = reject
      })
    })
  }
  /**分页查询 */
  page(pageNumber = 0, pageSize = 10) {
    return new Promise((resolve, reject) => {
      this.database.getDb().then((db) => {
        const tableStore = db.transaction([this.tableName], 'readonly').objectStore(this.tableName)
        const index = tableStore.index('id')
        const data = []
        const offset = pageNumber * pageSize
        let count = 0
        const q = index.openCursor()
        q.onsuccess = (event) => {
          const cursor = event.target.result
          if (cursor) {
            // 跳过前 offset 条
            if (count < offset) {
              count++
              cursor.continue()
              return
            }
            data.push(cursor.value)
            if (data.length < pageSize) {
              cursor.continue()
            } else {
              resolve({ data, total: count + data.length })
            }
          } else {
            resolve({ data, total: count })
          }
        }
        q.onerror = reject
      })
    })
  }
  /**
   * 删除数据
   * @param {string} id 键
   */
  deleteById(id) {
    return this.tableStoreHandle('delete', id)
  }
  /**
   * 清空所有数据
   */
  clear() {
    return this.tableStoreHandle('clear')
  }
}
